package apibasej.basic.misc.standalone;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class UtilReflectionField {
	
	// ESTA CLASSE TRATA O FIELD E/OU SEUS MÉTODOS GET E SET COMO UMA UNICA COISA

	private Field field = null;
	private Method methodGet = null;
	private Method methodSet = null;
	private boolean isFieldPublic = false;
	
	private Class<?> classFather;
	private String baseName = null; // NOME IGUAL DO FIELD OU NO PADRÃO DE NOME DO FIELD. EX: nomeAluno 
	private String nameVarXjpa = null;
	private Class<?> typeFieldPack = null;
	
	public UtilReflectionField(Field field) throws SecurityException, NoSuchMethodException{ //Class<?> classFather, String baseName
		
		this.classFather = field.getDeclaringClass();
		
		//this.baseName = baseName;
		//try { this.field = classFather.getDeclaredField(baseName); } catch (Exception e1) { }
		//if(this.field==null) try { this.field = classFather.getField(baseName); } catch (Exception e1) { }
		
		this.field = field;
		this.baseName = field.getName();
		
		this.isFieldPublic = (field!=null && Modifier.isPublic(field.getModifiers()) );
		
		StringBuilder nameMethodSet = new StringBuilder("set");
		nameMethodSet.append( Character.toUpperCase(baseName.charAt(0)) );
		nameMethodSet.append(baseName.substring(1));
		
		StringBuilder nameMethodGet = new StringBuilder("get");
		nameMethodGet.append( Character.toUpperCase(baseName.charAt(0)) );
		nameMethodGet.append(baseName.substring(1));
		
		if(field!=null) this.typeFieldPack = field.getType();
		
		if(!isFieldPublic){
			try{
				this.methodGet = classFather.getMethod(nameMethodGet.toString());
			}catch(NoSuchMethodException ex){
				// se não achou com get tenta com is
				if(baseName.startsWith("is")){//se o nome da variavel começa com is
					this.methodGet = classFather.getMethod(baseName);
				}else{
					StringBuilder nameMethodIs = new StringBuilder("is");
					nameMethodIs.append( Character.toUpperCase(baseName.charAt(0)) );
					nameMethodIs.append(baseName.substring(1));
					this.methodGet = classFather.getMethod(nameMethodIs.toString());
				}
			}
			
			if(this.typeFieldPack==null) {
				this.typeFieldPack = this.methodGet.getReturnType();
			}
			try{
				this.methodSet = classFather.getMethod(nameMethodSet.toString(), this.typeFieldPack );
			}catch(NoSuchMethodException ex){
				// se não achou o setIsBla tenta com o setBla
				if(baseName.startsWith("is")){
					nameMethodSet.delete(3,5);// apaga o trecho com Is 
					this.methodSet = classFather.getMethod(nameMethodSet.toString(), this.typeFieldPack );
				}else{
					throw ex;
				}
			}
			
		}
	}
	
	public void setValueInObject(Object objTarget, Object value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		//não usar primitivos!!!
		//[REVER] [LEMBRETE], VER NO MERGE, SE QUISER SETAR NULL 
		//SE VALUE FOR NULL NÃO SETAR, FICA O VALOR DEFAULT DO FIELD?
		//EVITA PROBLEMA DE SETAR NULL EM TIPOS PRIMITIVOS
		//if(value==null) return; // não pode ter esta linha ! nas entitys não se deve usar primitivos !
		
		if(methodSet!=null) methodSet.invoke(objTarget, value);
		else field.set(objTarget, value);
	}

	public Object getValueFromObject(Object objTarget) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		if(methodGet!=null) {
			return methodGet.invoke( classFather.cast(objTarget) );
		}
		else return field.get(objTarget);
	}
	
	
	
	public Class<?> getTypeFieldPack() {
		return typeFieldPack;
	}
	public String getBaseName() {
		return baseName;
	}
	public String getVarXjpaName() {
		return nameVarXjpa;
	}
	
	
	
}
